package com.ruoyi.framework.interceptor.impl

import com.alibaba.fastjson2.JSON
import com.ruoyi.common.constant.CacheConstants
import com.ruoyi.common.filter.RepeatedlyRequestWrapper
import com.ruoyi.common.utils.http.HttpHelper
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor
import com.ruoyi.framework.interceptor.annotation.RepeatSubmit
import com.ruoyi.framework.redis.RedisCache
import org.apache.commons.lang3.StringUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import java.util.concurrent.TimeUnit
import javax.servlet.http.HttpServletRequest

/**
 * 判断请求url和数据是否和上一次相同，
 * 如果和上次相同，则是重复提交表单。 有效时间为10秒内。
 *
 * @author ruoyi
 */
@Component
class SameUrlDataInterceptor : RepeatSubmitInterceptor() {
    private val REPEAT_PARAMS = "repeatParams"
    private val REPEAT_TIME = "repeatTime"

    // 令牌自定义标识
    @Value("\${token.header}")
    private val header: String? = null

    @Autowired
    private val redisCache: RedisCache? = null

    override fun isRepeatSubmit(request: HttpServletRequest, annotation: RepeatSubmit): Boolean {
        var nowParams: String? = ""
        if (request is RepeatedlyRequestWrapper) {
            nowParams = HttpHelper.getBodyString(request)
        }

        // body参数为空，获取Parameter的数据
        if (com.ruoyi.common.utils.StringUtils.isEmpty(nowParams)) {
            nowParams = JSON.toJSONString(request.parameterMap)
        }
        val nowDataMap: MutableMap<String, Any?> = HashMap()
        nowDataMap[REPEAT_PARAMS] = nowParams
        nowDataMap[REPEAT_TIME] = System.currentTimeMillis()

        // 请求地址（作为存放cache的key值）
        val url = request.requestURI

        // 唯一值（没有消息头则使用请求地址）
        val submitKey = StringUtils.trimToEmpty(request.getHeader(header))

        // 唯一标识（指定key + url + 消息头）
        val cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey
        val sessionObj = redisCache!!.getCacheObject(cacheRepeatKey)
        if (sessionObj != null) {
            val sessionMap = sessionObj as MutableMap<String, Any>
            if (sessionMap.containsKey(url)) {
                val preDataMap = sessionMap[url] as MutableMap<String, Any>?
                if (compareParams(nowDataMap, preDataMap) && compareTime(
                        nowDataMap,
                        preDataMap,
                        annotation.interval
                    )
                ) {
                    return true
                }
            }
        }
        val cacheMap: MutableMap<String, Any> = HashMap()
        cacheMap[url] = nowDataMap
        redisCache.setCacheObject<Map<String, Any>>(
            cacheRepeatKey,
            cacheMap,
            annotation.interval,
            TimeUnit.MILLISECONDS
        )
        return false
    }

    /**
     * 判断参数是否相同
     */
    private fun compareParams(nowMap: Map<String, Any?>, preMap: Map<String, Any>?): Boolean {
        val nowParams = nowMap[REPEAT_PARAMS] as String?
        val preParams = preMap!![REPEAT_PARAMS] as String?
        return nowParams == preParams
    }

    /**
     * 判断两次间隔时间
     */
    private fun compareTime(nowMap: Map<String, Any?>, preMap: Map<String, Any>?, interval: Int): Boolean {
        val time1 = nowMap[REPEAT_TIME] as Long
        val time2 = preMap!![REPEAT_TIME] as Long
        return time1 - time2 < interval
    }
}
